JavaScript 预处理

一、预处理

JavaScript 执行前,会对脚本、模块和函数体中的语句进行预处理。预处理过程会提前处理 var、let、const、function 声明和 class 声明这些语句,以确定其中变量的意义。

二、分类

1、var 声明

1.1、概念

var 声明永远作用于脚本、模块和函数体这个级别,在预处理阶段,不关心赋值的部分,只管在当前作用域声明这个变量。

1.2、穿透性

var 的作用能够穿透一切语句结构,它只认脚本、模块和函数体三种语法结构。

1.3、示例

1
2
3
4
5
6
7
8
9
10
11
12
var a = 1;

function foo() {
console.log(a);
if(false) {
var a = 2;
}
}

foo(); // undefined

// if(false) 中的代码永远不会被执行,但是预处理阶段并不管这个,var的作用能够穿透一切语句结构,它只认脚本、模块和函数体三种语法结构。所以这里结果跟前一段代码完全一样,我们会得到 undefined。

2、function 声明

2.1、概念

function 声明的行为原本跟 var 非常相似,但是在最新的 JavaScript 标准中,对它进行了一定的修改,即在全局(脚本、模块和函数体),function 声明表现跟 var 相似,不同之处在于 function 声明不但在作用域中加入变量,还会给它赋值

脚本中,如果变量和函数同名,那么函数将覆盖变量

2.2、穿透性

function 声明出现在 if 等语句中的情况有点复杂,它仍然作用于脚本、模块和函数体级别,在预处理阶段,仍然会产生变量,它不再被提前赋值

2.3、示例

1
2
3
4
5
6
console.log(foo); // undefined
if(true) {
function foo(){}
}

// 这段代码得到 undefined。如果没有函数声明,则会抛出错误。如果去掉 if 判断,则输出函数 foo。

3、class 声明

3.1、概念

class 声明在全局的行为跟 function 和 var 都不一样。在 class 声明之前使用 class 名,会抛错。

3.2、穿透性

class 的声明作用不会穿透 if 等语句结构,所以只有写在全局环境才会有声明作用

3.3、示例

1
2
3
4
5
6
7
var c = 1;
function foo(){
console.log(c);
class c {}
}
foo(); // Uncaught ReferenceError: Cannot access 'c' before initialization
// 执行后,抛出了错误,如果去掉 class 声明,则会正常打印出1

三、问题

示例一

1
2
3
4
5
6
var getName = function () { cnsole.log(1); };
function getName() { console.log(2); }

getName(); // 1
// 预处理阶段 先得到变量 getName,值为 undefined,之后变量 getName 被函数 getName 覆盖
// 运行阶段 函数 getName 对应的值被覆盖为 function () { cnsole.log(1); },所以运行时拿到的是这个内容,输出 1
微信打赏